package com.warrant.module.rpa.finance.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.codehaus.jettison.json.JSONException;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.eos.engine.component.ILogicComponent;
import com.eos.foundation.database.DatabaseExt;
import com.eos.foundation.database.DatabaseUtil;
import com.eos.system.annotation.Bizlet;
import com.primeton.ext.engine.component.LogicComponentFactory;
import com.warrant.module.rpa.finance.model.CollectionBill;
import com.warrant.module.rpa.finance.util.DataObjectConvertUtil;
import com.warrant.module.rpa.finance.util.ExcelUtils;
import com.warrant.module.rpa.finance.util.MatchUtil;

import commonj.sdo.DataObject;

/**
 * 到账流水service
 * 
 * @author cn
 * 
 */
@Bizlet
public class BillService {

	private static final Logger logger = Logger.getLogger(BillService.class);

	/**
	 * 保存数据源
	 * <p>
	 * 真难用,辣鸡EOS
	 * </p>
	 * 
	 * @param datas
	 *            银行流水实体列表
	 * @param datas
	 *            创建方式
	 */
	@Bizlet
	public static DataObject[] addBill(DataObject[] datas, String type) {
		if (datas.length > 0) {
			// 1 | 查找存在流水号 |
			List<String> noList = new ArrayList<String>();
			for (DataObject data : datas) {
				noList.add(data.getString("serialnumber"));
			}
			Map<String, List<String>> para = new HashMap<String, List<String>>();
			para.put("nums", noList);
			Object[] result = DatabaseExt.queryByNamedSql("default", "com.warrant.module.rpa.finance.billService.queryExistBillByNo", para);

			List<String> existNos = new ArrayList<String>();
			for (Object o : result) {
				existNos.add((String) o);
			}

			// 2 | 处理新增流水实体 |
			List<DataObject> billList = new ArrayList<DataObject>();
			for (int i = 0; i < datas.length; i++) {
				DataObject data = datas[i];
				if (!existNos.contains(data.getString("serialnumber"))) {
					// 获取主键
					DatabaseExt.getPrimaryKey(data);
					data.setDate("createtime", new Date());
					data.setString("createway", type);
					data.setString("isclaim", "1");
					data.setString("creator", "sys");
					billList.add(data);
				}
			}
			datas = billList.toArray(new DataObject[billList.size()]);

			// 3 | 批量新增流水 |
			if (billList.size() > 0) {
				DatabaseUtil.insertEntityBatch("default", datas);
			}
		}

		// 4 | 返回新增流水 |
		return datas;
	}

	/**
	 * 导入到账流水
	 * 
	 * @param filePath
	 * @throws IOException
	 * @throws JSONException
	 */
	@Bizlet
	public static void importBill(String filePath) throws Throwable {

		// 1 | excel导入 |
		List<CollectionBill> collectionBills = ExcelUtils.importExcel(filePath, 0, 1, CollectionBill.class);

		// 2 | 对象转换 |
		JSONArray collectionBillArr = (JSONArray) JSON.toJSON(collectionBills);
		DataObject[] datas = DataObjectConvertUtil.convertJsonStringToDataObjects("com.warrant.module.rpa.finance.data.BgCollectionBill", collectionBillArr.toJSONString());

		// 3 | 更新业务信息 |
		callLogicComponentByInsertBill(datas, "2");
	}

	/**
	 * 项目收款确认
	 * 
	 * @throws Throwable
	 */
	@Bizlet
	public static void pojectCollectionConfirm() throws Throwable {
		logger.info("项目收费确认开始");

		// 1 | 查找未收款充值记录 |
		Map<String, Object> para1 = new HashMap<String, Object>();
		Object[] notClaimRechargeArr = DatabaseExt.queryByNamedSql("default", "com.warrant.module.rpa.finance.accountService.queryNotClaimRechargeList", para1);

		// 2 | 查找未收款项目 |
		Map<String, Object> para2 = new HashMap<String, Object>();
		Object[] notCollectionProjectArr = DatabaseExt.queryByNamedSql("default", "com.warrant.module.rpa.finance.projectService.queryNotCollectionProjectList", para2);
		List<Object> notCollectionProjectList = new ArrayList(Arrays.asList(notCollectionProjectArr));

		// 2 | 项目收款确认 |
		/*
		 * 项目匹配规则： A轮： 1）、按照时间顺序，上次匹配时间查询充值记录表，根据项目名称一条条与符合条件直接匹配
		 * 2）、按照时间顺序，上次匹配时间查询充值记录表
		 * ，根据金额一条条与符合条件规则按照时间顺序，受理时间最早的项目则优先匹配.金额相等或者在误差范围内则自动匹配 B轮：
		 * 1）、符合条件规则按照时间顺序，受理时间最早的项目则优先匹配 2）、检查企业账户余额是否大于匹配项目金额，如果大于则优先匹配
		 */
		Map<String, Object> mapContext = new HashMap<String, Object>();
		for (Object o : notClaimRechargeArr) {
			DataObject rechargeObj = (DataObject) o;
			mapContext.put("recharge", rechargeObj);

			DataObject matchProject = matchProject(notCollectionProjectList, mapContext);
			if (matchProject != null) {
				System.out.println("匹配项目:" + matchProject);
				// 匹配项目,修改业务信息
				callLogicComponentByConsume(rechargeObj, matchProject);
				// 移除匹配项目
				notCollectionProjectList.remove(matchProject);
			}

		}
		logger.info("项目收费确认结束");
	}

	/**
	 * 流水匹配项目
	 * 
	 * @param projectList
	 * @param mapContext
	 * @return
	 */
	private static DataObject matchProject(List<Object> projectList, Map<String, Object> mapContext) {
		Long s = System.currentTimeMillis();
		DataObject rechargeObj = (DataObject) mapContext.get("recharge");

		// A轮
		List<DataObject> aRoundList = new ArrayList<DataObject>();
		for (int i = 0; i < projectList.size(); i++) {
			DataObject projectObj = (DataObject) projectList.get(i);
			mapContext.put("project", projectObj);

			// 规则1
			boolean flag1 = rule1(rechargeObj, projectObj);
			// boolean flag = MatchUtil.matchFastBoolean(ruleStr, mapContext);
			if (flag1) {
				aRoundList.clear();
				aRoundList.add(projectObj);
				break;
			}

			// 规则2
			boolean flag2 = rule2(rechargeObj, projectObj, new BigDecimal(10));
			if (flag2) {
				aRoundList.add(projectObj);
			}
		}

		Long e = System.currentTimeMillis();
		System.out.println("耗时" + (e - s));

		// 不存在 退出
		if (aRoundList.size() == 0) {
			return null;
		}
		// 只存在一个 直接匹配
		else if (aRoundList.size() == 1) {
			DataObject projectObj = aRoundList.get(0);
			return projectObj;
		}

		// B轮

		// 查询账户余额
		BigDecimal balance = queryAccountBalance(rechargeObj.getInt("accountId"));
		System.out.println("基本户余额:" + balance);

		// 项目时间排序
		Collections.sort(aRoundList, new Comparator<DataObject>() {
			public int compare(DataObject o1, DataObject o2) {
				// TODO 处理时间为空
				Date date1 = o1.getDate("projectTime");
				if (date1 == null)
					date1 = new Date();
				Date date2 = o2.getDate("projectTime");
				if (date2 == null)
					date2 = new Date();
				return date1.compareTo(date1);
			}
		});

		// 企业账户余额是否大于匹配项目金额
		for (int i = 0; i < aRoundList.size(); i++) {
			DataObject projectObj = aRoundList.get(i);

			// 项目收费
			BigDecimal amount = projectObj.getBigDecimal("amount");

			// 项目余额大于项目收费
			if (amount != null && balance.compareTo(amount) >= 0) {
				return projectObj;
			}
		}

		// Long e = System.currentTimeMillis();
		// System.out.println("耗时" + (e - s));

		return null;
	}

	/**
	 * 流水匹配客户
	 * 
	 * @param projectList
	 * @param mapContext
	 * @return
	 */
	@Bizlet
	public static DataObject matchBasicAccount(DataObject bill, DataObject[] customers, String rule) {
		Map mapContext = new HashMap<>();
		mapContext.put("bill", bill);
		for (DataObject customer : customers) {
			mapContext.put("customer", customer);
			if (MatchUtil.matchFastBoolean(rule, mapContext)) {
				return customer;
			}
		}
		return null;

	}

	/**
	 * 查询基本户余额
	 * 
	 * @param accountId
	 * @return
	 */
	private static BigDecimal queryAccountBalance(Integer accountId) {
		Map<String, Object> para = new HashMap<String, Object>();
		para.put("accountId", accountId);
		Object[] balanceObjs = DatabaseExt.queryByNamedSql("default", "com.warrant.module.rpa.finance.accountService.queryBasicAccountBalance", para);
		if (balanceObjs.length > 0) {
			return (BigDecimal) balanceObjs[0];
		}
		return new BigDecimal(0);
	}

	/**
	 * 调用新增到账流水逻辑流
	 * 
	 * @param data
	 *            流水实体列表
	 * 
	 * @param type
	 *            创建方式
	 * @return
	 * @throws Throwable
	 */
	public static void callLogicComponentByInsertBill(DataObject[] data, String type) throws Throwable {
		// 逻辑构件名称
		String componentName = "com.warrant.module.rpa.finance.billService";
		// 逻辑流名称
		String operationName = "insertBill";
		ILogicComponent logicComponent = LogicComponentFactory.create(componentName);
		int size = 2;
		// 逻辑流的输入参数
		Object[] params = new Object[size];
		params[0] = data;
		params[1] = type;
		logicComponent.invoke(operationName, params);
	}

	/**
	 * 调用消费逻辑流
	 * 
	 * @param data
	 *            流水实体列表
	 * @return
	 * @throws Throwable
	 */
	private static void callLogicComponentByConsume(DataObject recharge, DataObject project) throws Throwable {
		// 逻辑构件名称
		String componentName = "com.warrant.module.rpa.finance.billService";
		// 逻辑流名称
		String operationName = "consume";
		ILogicComponent logicComponent = LogicComponentFactory.create(componentName);
		int size = 2;
		// 逻辑流的输入参数
		Object[] params = new Object[size];
		params[0] = recharge;
		params[1] = project;
		logicComponent.invoke(operationName, params);
	}

	/**
	 * 匹配规则1
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	private static boolean rule1(DataObject a, DataObject b) {
		// 项目收费金额为空时跳过
		BigDecimal rechargeAmount = a.getBigDecimal("amount");
		BigDecimal projectAmount = b.getBigDecimal("amount");
		if (projectAmount == null) {
			return false;
		}
//		System.out.println(a.getInt("companyId") + "-----------------" + b.getInt("companyId"));
//		System.out.println(a.getString("projectName") + "-----------------" + b.getString("projectName"));
		return a.getInt("companyId") == b.getInt("companyId") && a.getString("projectName").equals(b.getString("projectName")) && rechargeAmount.compareTo(projectAmount) == 0;
	}

	/**
	 * 匹配规则2
	 * 
	 * @param a
	 *            充值信息
	 * @param b
	 *            项目信息
	 * @return
	 */
	private static boolean rule2(DataObject a, DataObject b, BigDecimal error) {
		// 项目收费金额为空时跳过
		BigDecimal rechargeAmount = a.getBigDecimal("amount");
		BigDecimal projectAmount = b.getBigDecimal("amount");
		if (projectAmount == null) {
			return false;
		}
		return a.getInt("companyId") == b.getInt("companyId") && rechargeAmount.subtract(projectAmount).compareTo(BigDecimal.ZERO) >= 0 && rechargeAmount.subtract(projectAmount).compareTo(error) <= 0;
	}

}
